    <template>
    <div>
        <el-form ref="form" label-width="80px" :model="spu">
            <el-form-item label="SPU名称">
                <el-input placeholder="SPU名称" v-model="spu.spuName"></el-input>
            </el-form-item>

            <el-form-item label="品牌">
                <el-select placeholder="请选则品牌" v-model="spu.tmId">
                    <el-option :label="tm.tmName" :value="tm.id" v-for="tm in resTradeMake" :key="tm.id"></el-option>
                </el-select>
            </el-form-item>

            <el-form-item label="SPU描述">
                <el-input type="textarea" placeholder="描述" v-model="spu.description"></el-input>
            </el-form-item>
            <!-- 
                    上传图片: action图片上传的地址 
                    list-type: 文件列表的类型
                    on- preview: 图片预览的时候会出发
                    on-remove: 当删除图片的时候会触发
                    file-list: 照片墙需要展示的数据[数组:数组里面的元素务必要有 name、url 属性
                    on-success: 文件上传成功的钩子
                -->
            <el-form-item label="SPU图片">
                <el-upload action="/dev-api/admin/product/fileUpload" list-type="picture-card"
                    :on-success="handlerSuccess" :on-preview="handlePictureCardPreview" :on-remove="handleRemove"
                    :file-list="spuImage">
                    <i class="el-icon-plus"></i>
                </el-upload>
                <el-dialog :visible.sync="dialogVisible">
                    <img width="100%" :src="dialogImageUrl" alt="">
                </el-dialog>
            </el-form-item>

            <el-form-item label="销售属性">
                <el-select :placeholder="`还有${unSelectSaleAtter.length}未选择`" v-model="attrIdAndName">
                    <el-option :label="unselect.name" :value="`${unselect.id}:${unselect.name}`"
                        v-for="unselect in unSelectSaleAtter" :key="unselect.id"></el-option>
                </el-select>

                <el-button type="primary" icon="el-icon-plus" :disabled="!attrIdAndName" @click="AddAttr">添加销售属性
                </el-button>

                <el-table style="width:100%" border :data="spu.spuSaleAttrList">
                    <el-table-column type="index" label="序号" align="center" width="80px"></el-table-column>
                    <el-table-column prop="saleAttrName" label="属性名" width="width"></el-table-column>
                    <el-table-column prop="description" label="属性值列表" width="width">
                        <template slot-scope="{row}">
                            <!-- 销售属性值  叉子点击事件@close="handleClose(tag)" -->
                            <el-tag :key="tag.id" v-for="(tag, index) in row.spuSaleAttrValueList" closable
                                :disable-transitions="false" @close="handleClose(row, index)">
                                {{ tag.saleAttrValueName }}
                            </el-tag>
                            <!-- input切换 @keyup.enter.native="handleInputConfirm" @blur="handleInputConfirm" -->
                            <el-input class="input-new-tag" v-if="row.inputVisible" v-model="row.inputValue"
                                ref="saveTagInput" size="small" @blur="handleInputConfirm(row)">
                            </el-input>
                            <!-- button切换 -->
                            <el-button v-else class="button-new-tag" @click="showInput(row)" size="small">添加</el-button>
                        </template>
                    </el-table-column>
                    <el-table-column prop="prop" label="操作" width="width">
                        <template slot-scope="{$index}">
                            <el-button type="danger" icon="el-icon-delete" size="small"
                                @click="spu.spuSaleAttrList.splice($index, 1)"></el-button>
                        </template>
                    </el-table-column>
                </el-table>
            </el-form-item>

            <el-form-item>
                <el-button type="primary" @click="SpuaddOrUpdata">保存</el-button>
                <el-button @click="Cancel">取消</el-button>
            </el-form-item>
        </el-form>
    </div>
</template>

    <script>
export default {
    data() {
        return {
            dialogImageUrl: '',
            dialogVisible: false,
            //从文档里面看，当保存的时候，会需要那么字段参数，我们就把这些参数移动到spu里面来
            spu: {
                //三级分类的id
                category3Id: 0,
                //描述
                description: "",
                //spu的名称
                spuName: "",
                // 品牌的id
                tmId: "",
                //收集spu图片的信息
                spuImageList: [
                    // {
                    //   id: 0,
                    //   imgName: "",
                    //   imgUrl: "",
                    //   spuId: 0,
                    // },
                ],
                //平台属性与属性值的收集 用于添加的操作
                spuSaleAttrList: [
                    // {
                    //   baseSaleAttrId: 0,
                    //   id: 0,
                    //   saleAttrName: "",
                    //   spuId: 0,
                    //   spuSaleAttrValueList: [
                    //     {
                    //       baseSaleAttrId: 0,
                    //       id: 0,
                    //       isChecked: "",
                    //       saleAttrName: "",
                    //       saleAttrValueName: "",
                    //       spuId: 0,
                    //     },
                    //   ],
                    // },
                ],
            },
            resTradeMake: [],
            spuImage: [],
            SaleAttrList: [],
            //收集未选择的销售属性的id和name用:分开
            attrIdAndName: '',
        };
    },
    methods: {
        // 初始化数据函数
        // refs被父组件调用的函数，触发这个函数时候，发送四个请求
        async initSpuData(row) {
            // console.log("row参数", row);
            // 获取SPU的信息
            let resSpu = await this.$API.spu.reqSpuInfo(row.id);
            if (resSpu.code == 200) {
                this.spu = resSpu.data;
            }
            // 获取品牌信息
            let resTradeMake = await this.$API.spu.reqTaderMarkList();
            if (resTradeMake.code == 200) {
                this.resTradeMake = resTradeMake.data;
            }
            // 获取spu图片
            let resSpuImage = await this.$API.spu.reqSpuImage(row.id);
            if (resSpuImage.code == 200) {
                let ArrList = resSpuImage.data;
                // 注意：在进行展示图片的时候，他识别是一个数组，数组里面的元素要有规定的字段：name、url才可以显示图片！
                // 所有我们需要把返回回来的数组重新处理一下，
                ArrList.forEach((item) => {
                    item.name = item.imgName;
                    item.url = item.imgUrl;
                });
                // 整理好之后，重新进行赋值
                this.spuImage = ArrList;
            }
            // 获取平台全部的销售属性
            let resSaleAttrList = await this.$API.spu.reqSaleAttrList();
            // console.log(resSaleAttrList);
            if (resSaleAttrList.code == 200) {
                this.SaleAttrList = resSaleAttrList.data;
            }
            // console.log('获取SPU的信息' + resSpu)
            // console.log('获取品牌信息' + resTradeMake)
            // console.log('获取spu图片' + resSpuImage)
            // console.log('获取平台全部的销售属性' + resSaleAttrList)
        },
        
        // 删除图片的时候触发 file 删除的那个图片, fileList删除那个图片后剩余的图片
        handleRemove(file, fileList) {
            // console.log(file, fileList);
            // 收集删除后的图片数据
            //对于已有的图片[照片钱中显示的图片:有name、url字段的]，因为照片墙显示数据务必要有这两个属性
            //对于服务器而言，不需要name、url字段，将来对于有的图片的数据在提交给服务器的时候，需要处理
            this.spuImage = fileList;
        },

        // 图片预览的时候会出发
        handlePictureCardPreview(file) {
            this.dialogImageUrl = file.url;
            this.dialogVisible = true;
        },

        // 图片上传成功的钩子函数
        handlerSuccess(response, file, fileList) {
            // response 上传是否成功后的数据
            // file  上传成功的数据
            // fileList 上传成功后的所有图片
            // 收集图片信息
            this.spuImage = fileList;
        },

        // 添加销售属性方法
        AddAttr() {
            // 把收集到的数据进行分割成数组,数组解构出我们需要的元素
            const [baseSaleAttrId, saleAttrName] = this.attrIdAndName.split(":");
            // 向spu对象的spuSaleAttrList属性里面添加新的销售属性
            let newSaleAttr = { baseSaleAttrId, saleAttrName, spuSaleAttrValueList: [] };
            // 给spu.spuSaleAttrList添加新的属性
            this.spu.spuSaleAttrList.push(newSaleAttr);
            // 每次点击添加之后，清除数据
            this.attrIdAndName = "";
        },

        // 新增标签属性按钮
        showInput(row) {
            // console.log(row);
            //点击销售属性值当中添加按钮的时候，需要有button变为input,通过当前销售属性的inputVisible控制  
            //挂载在销售属性身上的响应式数据inputVisible，控制button与input切换
            this.$set(row, "inputVisible", true);
            //通过响应式数据inputValue字段收集新增的销售属性值
            this.$set(row, "inputValue", "");
            this.$nextTick(()=> {
                // 让input聚焦
                this.$refs.saveTagInput.focus();

            })
        },

        // input失去焦点
        handleInputConfirm(row) {
            // console.log(row);
            // 把我们收集到的数据，追加到row.spuSaleAttrValueList里面，该有的属性一个都不能缺少
            // 解构出我们需要追加的参数【属性的id和输入新值的内容】
            const { baseSaleAttrId, inputValue } = row;
            // 判断是否为空数组
            if (row.inputValue.trim() == '') {
                this.$message({
                    message: '请不要添加空白属性~',
                    type: 'warning'
                });
                return
            }

            // 使用 every 判断用户输入的都是一样的属性
            let result = row.spuSaleAttrValueList.every(item => item.saleAttrValueName != inputValue);
            if (!result) {
                this.$message({
                    message: '请不要添加已有属性~',
                    type: 'warning'
                });
                return
            }


            // 这里使用 some 数组查重解决
            // let isReate = row.spuSaleAttrValueList.some(item => {
            //     // 需要将row从数组里面判断去除
            //     // row是数组的最新值 最新一项 item是每一项
            //     return inputValue == item.saleAttrValueName
            // })
            // console.log(isReate)
            // //row:形参是当前用户添加的最新的属性值
            // //当前编辑模式变为查看模式[让input消失，显示span]
            // // row新增的和上面的属性相同
            // if (isReate) {
            //     this.$message({
            //         message: '请不要添加已有属性~',
            //         type: 'warning'
            //     });
            //     return
            // }
            // 新增销售属性值
            let newSaleAttrValueList = { baseSaleAttrId, saleAttrValueName: inputValue };
            // 添加数据标签
            row.spuSaleAttrValueList.push(newSaleAttrValueList);
            // 修改为false
            row.inputVisible = false;
        },

        // 点击叉子的函数
        handleClose(row, index) {
            // console.log(row)
            row.spuSaleAttrValueList.splice(index, 1)
        },

        // 保存按钮回调函数
        async SpuaddOrUpdata() {
            //处理一下图片的数据，因为带给服务器的字段是：imgName，imgUrl。我们添加的新图数据没有这些字段，所有需要把这个俩个字段添加我们的新元素里
            // map：把遍历的每一个值进行可控的变化，返回给原数组。不会产生新数组
            this.spu.spuImageList = this.spuImage.map(item => {
                return {
                    imgName: item.name,
                    // 注意：需要判断一下，新添的数据里面有没有response和response.data，有我才添加imgUrl。不能把原有的数据也替换了(自身具有)，
                    imgUrl: (item.response && item.response.data) || item.url,
                };
            });
            // 发送请求
            let result = await this.$API.spu.reqAddOrUpdateSpu(this.spu);
            if (result.code == 200) {
                // 提示
                this.$message({
                    message: this.spu.id ? '修改成功~' : '添加成功~',
                    type: 'success'
                });
                // 通知父亲 变成 0 展示列表
                this.$emit('changeScene', { scene: 0, flag: this.spu.id ? '修改' : '添加' })
            }

            // 清除数据
            //Object.assign:es6中新增的方法可以合并对象
            //组件实例this._data,可以操作data当中响应式数据
            //this.$options可以获取配置对象，配置对象的data函数执行，返回的响应式数据为空的
            Object.assign(this._data, this.$options.data());
        },


        // 添加发送请求
        async addSupData(category3Id) {
            // 收集传过来的三级分类ID
            this.spu.category3Id = category3Id;
            // 获取品牌信息
            let resTradeMake = await this.$API.spu.reqTaderMarkList();
            if (resTradeMake.code == 200) {
                this.resTradeMake = resTradeMake.data;
            }
            // 获取平台全部的销售属性
            let resSaleAttrList = await this.$API.spu.reqSaleAttrList();
            // console.log(resSaleAttrList);
            if (resSaleAttrList.code == 200) {
                this.SaleAttrList = resSaleAttrList.data;
            }
        },

        // 取消按钮的函数
        Cancel() {
            //通知父组件，切换场景为SPU展示列表，但是我们这里需要区分一下。取消的时候添加|修改区域。传递一个对象给父组件
            this.$emit("changeScene", {
                scene: 0,
                // 如果spu有id，就是修改，反之就是添加
                flag: this.spu.id ? "修改" : "添加",
            });
            //  清除数据
            //  Object.assign:es6中新增的方法可以合并对象
            //  组件实例this._data,可以操作data当中响应式数据
            //  this.$options可以获取配置对象，配置对象的data函数执行，返回的响应式数据为空的
            //  这里面如果后面有前面的属性则会覆盖前面的属性 然后再合并对象
            Object.assign(this._data, this.$options.data());
            // console.log(this._data, this.$options.data())
        },

    },

    computed: {
        // 计算出未选择的属性【需要返回一个函数才能生效计算属性】
        unSelectSaleAtter() {
            //整个平台的销售属性一共三个：尺寸、颜色、版本 ----saleAttrList
            //当前SPU拥有的属于自己的销售属性SPU.spuSaleAttrList  ----颜色
            //数组的过滤方法，可以从已有的数组当中过滤出用户需要的元素，并未返回一个新的数据
            let ruslt = this.SaleAttrList.filter((item) => {
                // console.log(item);
                // every方法：跟自己判断的结果相等，返回就是一个布尔值为true
                return this.spu.spuSaleAttrList.every((item1) => {
                    // console.log(item.name,item1.saleAttrName)
                    // console.log(item.name !== item1.saleAttrName)
                    return item.name !== item1.saleAttrName; //如果不等于，返回结果为真
                });
            });
            return ruslt;
        }
    }
}
</script>


<style>
.el-tag+.el-tag {
    margin-left: 10px;
}

.button-new-tag {
    margin-left: 10px;
    height: 32px;
    line-height: 30px;
    padding-top: 0;
    padding-bottom: 0;
}

.input-new-tag {
    width: 90px;
    margin-left: 10px;
    vertical-align: bottom;
}
</style>